#include "byte_ring_buffer.h"

CByteRingBuffer::CByteRingBuffer(unsigned int pSize) :
	mBuffer(pSize),
	mPut(0),
	mGet(0),
	mFull(false)
{

}

CByteRingBuffer::~CByteRingBuffer()
{

}

void CByteRingBuffer::put(unsigned char pValue)
{
	if (mPut == mGet && mFull) {
		mGet++;

		if (mGet == mBuffer.size()) {
			mGet = 0;
		}
	}

	mBuffer[mPut++] = pValue;

	if (mPut == mBuffer.size()) {
		mPut = 0;
	}

	if (mGet == mPut) {
		mFull = true;
	}
}

void CByteRingBuffer::put(void* pValues, unsigned int pCount)
{
	if (!pValues) { // fill with zeros
		for (unsigned int i = 0; i < pCount; i++) {
			put(0);
		}
	}
	else { // normal mode
		for (unsigned int i = 0; i < pCount; i++) {
			put(reinterpret_cast<unsigned char*>(pValues)[i]);
		}
	}
}

unsigned int CByteRingBuffer::get(void* pDst, unsigned int pCount, bool pClean)
{
	if (!pDst || !pCount) {
		return 0;
	}

	int lIndex;
	unsigned int i(0);
	for (; i < pCount; i++) {
		lIndex = getIndex(i);
		if (lIndex < 0) {
			goto out;
		}
		static_cast<unsigned char*>(pDst)[i] = mBuffer[lIndex];
	}

out:
	if (pClean) {
		clean(i);
	}
	return i;
}

int CByteRingBuffer::getIndex(int pOffset)
{
	if (pOffset < 0 || static_cast<unsigned int>(pOffset) >= len()) {
		return -1;
	}

	unsigned int lIndex(mGet + pOffset);
	if (lIndex >= mBuffer.size()) {
		lIndex -= mBuffer.size();
	}

	return static_cast<int>(lIndex);
}

unsigned int CByteRingBuffer::clean(unsigned int pLen)
{
	for (unsigned int i = 0; i < pLen; i++) {
		if (!cleanFirst()) {
			return i;
		}
	}

	return pLen;
}

bool CByteRingBuffer::cleanFirst()
{
	if (mGet == mPut && !mFull) {
		// empty
		return false;
	}
	
	mGet++;
	if (mGet >= mBuffer.size()) {
		mGet = 0;
	}

	mFull = false;
	return true;
}

unsigned int CByteRingBuffer::len()
{
	if (mPut > mGet) {
		return mPut - mGet;
	} else if (mPut < mGet) {
		return (mPut + mBuffer.size()) - mGet;
	} else {
		return mFull ? mBuffer.size() : 0;
	}
}

unsigned int CByteRingBuffer::size()
{
	return mBuffer.size();
}

